using System;
using System.Collections.Generic;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Diagnostics;
using SPTraceView.Model;
using System.Runtime.InteropServices;
using System.IO;
using System.Threading;
using System.Security.Principal;


namespace SPTraceView
{
	public partial class frmMain : Form
	{

		internal enum VirtualKeyStates : int
		{
			VK_LBUTTON = 0x01,
			VK_RBUTTON = 0x02,
			VK_CANCEL = 0x03,
			VK_MBUTTON = 0x04,
			////
			//VK_XBUTTON1 = 0x05,
			//VK_XBUTTON2 = 0x06,
			////
			//VK_BACK = 0x08,
			//VK_TAB = 0x09,
			////
			//VK_CLEAR = 0x0C,
			//VK_RETURN = 0x0D,
			////
			//VK_SHIFT = 0x10,
			//VK_CONTROL = 0x11,
			//VK_MENU = 0x12,
			//VK_PAUSE = 0x13,
			//VK_CAPITAL = 0x14,
			////
			//VK_KANA = 0x15,
			//VK_HANGEUL = 0x15,  /* old name - should be here for compatibility */
			//VK_HANGUL = 0x15,
			//VK_JUNJA = 0x17,
			//VK_FINAL = 0x18,
			//VK_HANJA = 0x19,
			//VK_KANJI = 0x19,
			////
			//VK_ESCAPE = 0x1B,
			////
			//VK_CONVERT = 0x1C,
			//VK_NONCONVERT = 0x1D,
			//VK_ACCEPT = 0x1E,
			//VK_MODECHANGE = 0x1F,
			////
			//VK_SPACE = 0x20,
			//VK_PRIOR = 0x21,
			//VK_NEXT = 0x22,
			//VK_END = 0x23,
			//VK_HOME = 0x24,
			//VK_LEFT = 0x25,
			//VK_UP = 0x26,
			//VK_RIGHT = 0x27,
			//VK_DOWN = 0x28,
			//VK_SELECT = 0x29,
			//VK_PRINT = 0x2A,
			//VK_EXECUTE = 0x2B,
			//VK_SNAPSHOT = 0x2C,
			//VK_INSERT = 0x2D,
			//VK_DELETE = 0x2E,
			//VK_HELP = 0x2F,
			////
			//VK_LWIN = 0x5B,
			//VK_RWIN = 0x5C,
			//VK_APPS = 0x5D,
			////
			//VK_SLEEP = 0x5F,
			////
			//VK_NUMPAD0 = 0x60,
			//VK_NUMPAD1 = 0x61,
			//VK_NUMPAD2 = 0x62,
			//VK_NUMPAD3 = 0x63,
			//VK_NUMPAD4 = 0x64,
			//VK_NUMPAD5 = 0x65,
			//VK_NUMPAD6 = 0x66,
			//VK_NUMPAD7 = 0x67,
			//VK_NUMPAD8 = 0x68,
			//VK_NUMPAD9 = 0x69,
			//VK_MULTIPLY = 0x6A,
			//VK_ADD = 0x6B,
			//VK_SEPARATOR = 0x6C,
			//VK_SUBTRACT = 0x6D,
			//VK_DECIMAL = 0x6E,
			//VK_DIVIDE = 0x6F,
			//VK_F1 = 0x70,
			//VK_F2 = 0x71,
			//VK_F3 = 0x72,
			//VK_F4 = 0x73,
			//VK_F5 = 0x74,
			//VK_F6 = 0x75,
			//VK_F7 = 0x76,
			//VK_F8 = 0x77,
			//VK_F9 = 0x78,
			//VK_F10 = 0x79,
			//VK_F11 = 0x7A,
			//VK_F12 = 0x7B,
			//VK_F13 = 0x7C,
			//VK_F14 = 0x7D,
			//VK_F15 = 0x7E,
			//VK_F16 = 0x7F,
			//VK_F17 = 0x80,
			//VK_F18 = 0x81,
			//VK_F19 = 0x82,
			//VK_F20 = 0x83,
			//VK_F21 = 0x84,
			//VK_F22 = 0x85,
			//VK_F23 = 0x86,
			//VK_F24 = 0x87,
			////
			//VK_NUMLOCK = 0x90,
			//VK_SCROLL = 0x91,
			////
			//VK_OEM_NEC_EQUAL = 0x92,   // '=' key on numpad
			////
			//VK_OEM_FJ_JISHO = 0x92,   // 'Dictionary' key
			//VK_OEM_FJ_MASSHOU = 0x93,   // 'Unregister word' key
			//VK_OEM_FJ_TOUROKU = 0x94,   // 'Register word' key
			//VK_OEM_FJ_LOYA = 0x95,   // 'Left OYAYUBI' key
			//VK_OEM_FJ_ROYA = 0x96,   // 'Right OYAYUBI' key
			////
			//VK_LSHIFT = 0xA0,
			//VK_RSHIFT = 0xA1,
			//VK_LCONTROL = 0xA2,
			//VK_RCONTROL = 0xA3,
			//VK_LMENU = 0xA4,
			//VK_RMENU = 0xA5,
			////
			//VK_BROWSER_BACK = 0xA6,
			//VK_BROWSER_FORWARD = 0xA7,
			//VK_BROWSER_REFRESH = 0xA8,
			//VK_BROWSER_STOP = 0xA9,
			//VK_BROWSER_SEARCH = 0xAA,
			//VK_BROWSER_FAVORITES = 0xAB,
			//VK_BROWSER_HOME = 0xAC,
			////
			//VK_VOLUME_MUTE = 0xAD,
			//VK_VOLUME_DOWN = 0xAE,
			//VK_VOLUME_UP = 0xAF,
			//VK_MEDIA_NEXT_TRACK = 0xB0,
			//VK_MEDIA_PREV_TRACK = 0xB1,
			//VK_MEDIA_STOP = 0xB2,
			//VK_MEDIA_PLAY_PAUSE = 0xB3,
			//VK_LAUNCH_MAIL = 0xB4,
			//VK_LAUNCH_MEDIA_SELECT = 0xB5,
			//VK_LAUNCH_APP1 = 0xB6,
			//VK_LAUNCH_APP2 = 0xB7,
			////
			//VK_OEM_1 = 0xBA,   // ';:' for US
			//VK_OEM_PLUS = 0xBB,   // '+' any country
			//VK_OEM_COMMA = 0xBC,   // ',' any country
			//VK_OEM_MINUS = 0xBD,   // '-' any country
			//VK_OEM_PERIOD = 0xBE,   // '.' any country
			//VK_OEM_2 = 0xBF,   // '/?' for US
			//VK_OEM_3 = 0xC0,   // '`~' for US
			////
			//VK_OEM_4 = 0xDB,  //  '[{' for US
			//VK_OEM_5 = 0xDC,  //  '\|' for US
			//VK_OEM_6 = 0xDD,  //  ']}' for US
			//VK_OEM_7 = 0xDE,  //  ''"' for US
			//VK_OEM_8 = 0xDF,
			////
			//VK_OEM_AX = 0xE1,  //  'AX' key on Japanese AX kbd
			//VK_OEM_102 = 0xE2,  //  "<>" or "\|" on RT 102-key kbd.
			//VK_ICO_HELP = 0xE3,  //  Help key on ICO
			//VK_ICO_00 = 0xE4,  //  00 key on ICO
			////
			//VK_PROCESSKEY = 0xE5,
			////
			//VK_ICO_CLEAR = 0xE6,
			////
			//VK_PACKET = 0xE7,
			////
			//VK_OEM_RESET = 0xE9,
			//VK_OEM_JUMP = 0xEA,
			//VK_OEM_PA1 = 0xEB,
			//VK_OEM_PA2 = 0xEC,
			//VK_OEM_PA3 = 0xED,
			//VK_OEM_WSCTRL = 0xEE,
			//VK_OEM_CUSEL = 0xEF,
			//VK_OEM_ATTN = 0xF0,
			//VK_OEM_FINISH = 0xF1,
			//VK_OEM_COPY = 0xF2,
			//VK_OEM_AUTO = 0xF3,
			//VK_OEM_ENLW = 0xF4,
			//VK_OEM_BACKTAB = 0xF5,
			////
			//VK_ATTN = 0xF6,
			//VK_CRSEL = 0xF7,
			//VK_EXSEL = 0xF8,
			//VK_EREOF = 0xF9,
			//VK_PLAY = 0xFA,
			//VK_ZOOM = 0xFB,
			//VK_NONAME = 0xFC,
			//VK_PA1 = 0xFD,
			//VK_OEM_CLEAR = 0xFE
		}

		[DllImport("user32.dll")]
		private static extern short GetKeyState(VirtualKeyStates nVirtKey);

		internal class BallooneEntry
		{
			internal readonly string Title;
			internal readonly string Text;
			internal readonly ToolTipIcon Icon;

			public BallooneEntry(string title, string text, ToolTipIcon icon)
			{
				Title = title;
				Text = text;
				Icon = icon;
			}
		}

		private TraceConsumer m_TraceConsumer;
		internal static bool s_ShutDown = false; /* If true, this indicates a genuine shutdown request, otherwise the form with cancel the close request in FormClose*/
		private bool m_Initialized = false; /* True after the FormLoad has been called and settings have been loaded */
		private bool m_ShutdownCompleted = false; /* Used to track whether the shutdown sequence has been completed so we don't reenter the FormClose() */
		private bool m_TraceLogEnabled = false; /* True if the trace log is available to be displays. The value is false once we have started shutdown and for the first welcome message. */
		private bool m_Enabled = false; /* Global Enable/Disable flag done from the tray icon */
		private bool m_DontShowBalloonsFor5Secs = false; /* Set to true if the pop-up menu is shown. In this case no messages are shown in the next 5 sec, that would show on the top of the pop-up menu */
		private int m_ErrorStarting = 0; /* The error returned by ProcessTrace(). */

		private int m_BallooneToolTipTicks = 0;
		private long m_TimerTicks = 0;
		private TraceSettings m_Settings;
		private MyTraceLogFile m_TraceLog;
		private object m_SyncRoot = new object();

		private Queue<BallooneEntry> m_BalloonesQueue = new Queue<BallooneEntry>();
		private Icon m_SPTraceViewIcon;
		private Bitmap m_SPTraceViewDisabledBitmap;
		private Icon m_SPTraceViewDisabledIcon;

		private static string s_NewVersion = null;
		private static string s_NewVersionDate = null;

		public static void IsNewVersion(string arg1, string arg2)
		{
			try
			{
				s_NewVersion = arg1;// Updater.VersionToVersionString(int.Parse(arg1));
			}
			catch (FormatException)
			{ }

			s_NewVersionDate = arg2;
		}

		public frmMain()
		{
			InitializeComponent();

			if (Environment.CommandLine != null)
			{
				string[] args = Environment.CommandLine.Split(new string[] { ";$#" }, StringSplitOptions.RemoveEmptyEntries);
				if (args.Length == 4 &&
					File.Exists(args[1]))
				{
					try
					{
						File.Delete(args[1]);
					}
					catch (Exception ex)
					{
						Trace.WriteLine(ex.ToString(), "SPTraceView");
					}

					IsNewVersion(args[2], args[3]);
				}
			}

			m_SPTraceViewIcon = Icon.FromHandle(Properties.Resources.WSS.GetHicon());
			m_SPTraceViewDisabledBitmap = new Bitmap(Properties.Resources.WSS);
			int maxPos = Math.Min(m_SPTraceViewDisabledBitmap.Width, m_SPTraceViewDisabledBitmap.Height);
			int xOffset = (m_SPTraceViewDisabledBitmap.Width - maxPos) / 2;
			int yOffset = (m_SPTraceViewDisabledBitmap.Height - maxPos) / 2;
			for (int i = 1; i < maxPos; i++)
			{
				m_SPTraceViewDisabledBitmap.SetPixel(xOffset + i, yOffset + i, Color.Red);
				m_SPTraceViewDisabledBitmap.SetPixel(xOffset + i, m_SPTraceViewDisabledBitmap.Height - yOffset - i, Color.Red);
			}
			m_SPTraceViewDisabledIcon = Icon.FromHandle(m_SPTraceViewDisabledBitmap.GetHicon());
			
			this.Icon = m_SPTraceViewIcon;
			notifyIcon.Icon = m_SPTraceViewIcon;

			m_Settings = new TraceSettings(false);

			UDPHelper.Init(ProcessTraceEvent, m_Settings.FarmRole);

			m_TraceConsumer = new TraceConsumer(TraceEvent, m_Settings);
			m_TraceLog = new MyTraceLogFile();

			//PerformStartUp(true);

			notifyIcon.Visible = true;

			m_ErrorStarting = m_TraceConsumer.Run();

			if (m_ErrorStarting == 0)
			{
				if (s_NewVersion != null)
					notifyIcon.ShowBalloonTip(10000, "SPTraceView has been updated", string.Format("SPTraceView has been updated to version {0} released on {1}.", s_NewVersion, s_NewVersionDate), ToolTipIcon.Info);
				else
					notifyIcon.ShowBalloonTip(10000, "SPTraceView is running", "SPTraceView is now listening for trace events. Right click on the icon for more options.", ToolTipIcon.Info);
			}
			else
			{
				clbLevels.Enabled = false;
				lblMonitoredLevels.Enabled = false;

				if (m_ErrorStarting == 5)
					notifyIcon.ShowBalloonTip(30000, "Error running SPTraceView", "SPTraceView cannot start listening for trace events. Make sure you have sufficient privilegies. You still may be able to receive events from remote Farm Trace Providers.", ToolTipIcon.Warning);
				else if (m_ErrorStarting == 4201)
					notifyIcon.ShowBalloonTip(30000, "Error running SPTraceView", "SPTraceView cannot start listening for trace events. Make sure the 'Windows SharePoint Services Tracing' service is running. You still may be able to receive events from remote Farm Trace Providers.", ToolTipIcon.Warning);
				else
					notifyIcon.ShowBalloonTip(30000, "Error running SPTraceView", "SPTraceView cannot start listening for trace events. The error returned is 0x" + Convert.ToString(m_ErrorStarting, 16) + ". You still may be able to receive events from remote Farm Trace Providers.", ToolTipIcon.Warning);
			}

			// toolTipTimer.Enabled = true;

			// Because the message pump is already working, this "Invoke" will send a message to load the form
			// frmMain_Load is not normally called because we use Application.Run() rather than Applcation.Run(Form)
			IntPtr cheat = this.Handle;
			if (!IntPtr.Zero.Equals(cheat))
				this.Invoke(new FormLoadDelegate(frmMain_Load), new object[] { this, EventArgs.Empty });

			//AppDomain.CurrentDomain.SetPrincipalPolicy(PrincipalPolicy.WindowsPrincipal);
			//WindowsPrincipal windowsPrincipal = (WindowsPrincipal)Thread.CurrentPrincipal;
			//if (windowsPrincipal.IsInRole(WindowsBuiltInRole.Administrator) ||
			//    windowsPrincipal.IsInRole(WindowsBuiltInRole.PowerUser)
			//    )
			//{
			//    CheckForUpdatesDelegate checkForUpdates = new CheckForUpdatesDelegate(CheckForUpdates);
			//    checkForUpdates.BeginInvoke(null, null);
			//}
		}

		private bool m_NewUpdateAvailable = false;

        //private void CheckForUpdates()
        //{
        //    try
        //    {
        //        Updater upd = new Updater();
        //        m_NewUpdateAvailable = upd.NewUpdatesAvailable() != null;
        //    }
        //    catch (Exception ex)
        //    {
        //        Trace.WriteLine(ex.ToString(), "SPTraceView");
        //    }
        //}

		private delegate void CheckForUpdatesDelegate();
		private delegate void FormLoadDelegate(object sender, EventArgs e);

		private void SuggestUpdate()
		{
			Trace.WriteLine("Initiating update to a new version ...", "SPTraceView");

			PerformShutdownButDontQuit();

			m_TraceConsumer.Stop();

			// Setting to false, back to true and back to false, forces any unclosed tips to be closed
			notifyIcon.Visible = false;
			notifyIcon.Visible = true;
			notifyIcon.Visible = false;

			m_ShutdownCompleted = true;

			if (MessageBox.Show(this, "There is a new version of SPTraceView available. Press OK to update now.", "SPTraceView", MessageBoxButtons.OKCancel, MessageBoxIcon.Question) == DialogResult.OK)
			{
				string tempPath = Path.ChangeExtension(Path.GetTempFileName(), ".exe");

				using (Stream resStream = SPTraceView.Helpers.AssemblyHelper.GetEmbededResourceStreamThatClientMustDispose("SPTraceView", "Updater.bin"))
				using (FileStream outFile = new FileStream(tempPath, FileMode.Create, FileAccess.Write))
				{
					resStream.Position = 0;
					byte[] buffer = new byte[resStream.Length];
					resStream.Read(buffer, 0, (int)resStream.Length);
					outFile.Write(buffer, 0, (int)resStream.Length);
				}


				ProcessStartInfo pi = new ProcessStartInfo(tempPath, Application.ExecutablePath);
				pi.CreateNoWindow = false;
				pi.WindowStyle = ProcessWindowStyle.Hidden;

				Process.Start(pi);
			}

			Application.Exit();
		}

		private void frmMain_Load(object sender, EventArgs e)
		{
			if (!m_Initialized)
			{
				clbLevels.Items.Clear();
				clbLevels.Items.AddRange(TraceSeverityEntry.AllTraceSeverityEntries);

				m_TraceConsumer.EnableEventFiring();

				toolTipTimer.Enabled = true;
				m_Enabled = true;
				miEnabledDisabled.Image = Properties.Resources.WSS;
				miEnabledDisabled.Text = "&Disable";
				notifyIcon.Icon = m_SPTraceViewIcon;
				Update();

				LoadSettings();

				m_Initialized = true;
			}
		}

		private void LoadSettings()
		{
			for (int i = 0; i < clbLevels.Items.Count; i++)
			{
				clbLevels.SetItemChecked(i, false);

				foreach (ULS.TraceSeverity severity in m_Settings.MonitoredLevels)
				{
					if (((TraceSeverityEntry)clbLevels.Items[i]).TraceSeverity == severity)
					{
						clbLevels.SetItemChecked(i, true);
						break;
					}
				}
			}

			cbxSaveToMyEvents.Checked = m_Settings.TraceToMyEventsLog;
			cbxShowBalloone.Checked = m_Settings.TraceShowBalloone;
			cbxTraceInDebugView.Checked = m_Settings.TraceToDebugView;
		}

		private void ProcessTraceEvent(
			string serverName,
			ULS.TraceSeverity severity,
			long timeStamp,
			uint processId,
			string exeName,
			string product,
			string category,
			string message,
			Int64 timeCorrection,
			DateTime eventTime)
		{
			m_TraceLogEnabled = true;

			if (!m_Enabled)
				return;

			lock (m_SyncRoot)
			{
				if (m_Settings.TraceToMyEventsLog)
				{
					m_TraceLog.TraceEvent(serverName, severity, timeStamp, processId, exeName, product, category, message, timeCorrection);
				}

				if (m_Settings.TraceToDebugView)
				{
					Trace.WriteLine(string.Format("Time: {3}, Timestamp: {0}, ProcessId: {1}, ExeName: {2}", timeStamp, processId, exeName, eventTime.ToString("dd MMM, HH:mm:ss.fffff")));
					Trace.WriteLine(string.Format("Machine: {0}, Severity: {1}, Product: '{2}', Category: '{3}'", serverName, severity, product, category));
					Trace.WriteLine(message);
					Trace.WriteLine("\r\n\r\n");
				}

				if (m_Settings.TraceShowBalloone)
				{
					ToolTipIcon icon = IconForEventSeverity(severity);
					lock (m_BalloonesQueue)
					{
						string ballooneTitle = serverName == "localhost" ? product : serverName + ": " +product;
						m_BalloonesQueue.Enqueue(new BallooneEntry(ballooneTitle, message, icon));
					}
				}
			}
		}

		private void TraceEvent(TraceEventArgs e)
		{
			Debug.WriteLine("frmMain.TraceEvent");

			ULS.ULSTraceHeader traceData = e.Event;
			ULS.TraceSeverity severity = e.Severity;
			ETW.EVENT_TRACE eventTrace = e.RawTraceData;

			StringBuilder fullMessage = new StringBuilder();

			if (e.MultiLinesEvent != null)
			{
				traceData = e.MultiLinesEvent.Event1;

				if (e.MultiLinesEvent.NumberOfParts > 0)
					fullMessage.Append(e.MultiLinesEvent.Event1.Message);

				if (e.MultiLinesEvent.NumberOfParts > 1)
					fullMessage.Append(e.MultiLinesEvent.Event2.Message);

				if (e.MultiLinesEvent.NumberOfParts > 2)
					fullMessage.Append(e.MultiLinesEvent.Event3.Message);

				if (e.MultiLinesEvent.NumberOfParts > 3)
					fullMessage.Append(e.MultiLinesEvent.Event4.Message);

				if (e.MultiLinesEvent.NumberOfParts > 4)
					fullMessage.Append(e.MultiLinesEvent.Event5.Message);
			}
			else
			{
				fullMessage.Append(traceData.Message);
			}

			string message = fullMessage.ToString();

			DateTime eventTime = DateTime.FromFileTime(eventTrace.Header.TimeStamp + e.TimeCorrection);
			ProcessTraceEvent("localhost", severity, eventTrace.Header.TimeStamp, eventTrace.Header.ProcessId, traceData.ExeName, traceData.Product, traceData.Category, message, e.TimeCorrection, eventTime);

			if (m_Enabled &&
				m_Settings.FarmRole.m_FarmRole == TraceViewFarmRole.Server)
			{
				UDPHelper.Send(
					severity, 
					eventTrace.Header.TimeStamp, 
					eventTrace.Header.ProcessId, 
					traceData.ExeName, 
					traceData.Product, 
					traceData.Category,
					message, 
					eventTime);
			}
		}

		private ToolTipIcon IconForEventSeverity(ULS.TraceSeverity severity)
		{
			switch (severity)
			{
				case ULS.TraceSeverity.CriticalEvent:
				case ULS.TraceSeverity.Exception:
				case ULS.TraceSeverity.Unexpected:
				case ULS.TraceSeverity.High:
				case ULS.TraceSeverity.Medium:
					return ToolTipIcon.Error;
					
				case ULS.TraceSeverity.Assert:
				case ULS.TraceSeverity.Unassigned:
				case ULS.TraceSeverity.WarningEvent:
					return ToolTipIcon.Warning;

				case ULS.TraceSeverity.Monitorable:
				case ULS.TraceSeverity.InformationEvent:
				case ULS.TraceSeverity.Verbose:
					return ToolTipIcon.Info;
			}

			return ToolTipIcon.None;
		}

		private void linkLabel1_LinkClicked(object sender, LinkLabelLinkClickedEventArgs e)
		{
			Process.Start("http://technet.microsoft.com/en-au/sysinternals/bb896647.aspx");
		}

		private void frmMain_FormClosing(object sender, FormClosingEventArgs e)
		{
			if (!m_ShutdownCompleted)
			{
				if (e.CloseReason == CloseReason.UserClosing &&
					!s_ShutDown)
				{
					Hide();
					notifyIcon.Visible = true;
					e.Cancel = true;
				}
				else
				{
					Cursor = Cursors.WaitCursor;
					
					Update();
					lock (m_BalloonesQueue)
					{
						m_BalloonesQueue.Clear();
						notifyIcon.ContextMenu = null;
						m_TraceLogEnabled = false;
						notifyIcon.ShowBalloonTip(30000, "Waiting to close ...", "SPTraceView is releasing system resources. Please be patient, this may take a few moments.", ToolTipIcon.Info);
					}

					try
					{
						notifyIcon.Text = "SPTraceView (Waiting to close ...)";

						PerformShutdownButDontQuit();

						m_TraceConsumer.Stop();

						// Setting to false, back to true and back to false, forces any unclosed tips to be closed
						notifyIcon.Visible = false;
						notifyIcon.Visible = true;
						notifyIcon.Visible = false;

						m_ShutdownCompleted = true;

						Application.Exit();
					}
					finally
					{
						Cursor = Cursors.Default;
					}
				}
			}
		}

		private void PerformShutdownButDontQuit()
		{
			m_Enabled = false;

			if (m_LogViewer != null) m_LogViewer.Hide();
			Hide();

			notifyIcon.Icon = Icon.FromHandle(Cursors.WaitCursor.Handle);

			UDPHelper.Close();

			if (m_LogViewer != null) m_LogViewer.Hide();
			Hide();

			m_TraceConsumer.DisableEventFiring();

			toolTipTimer.Enabled = false;
			m_TraceLog.Flush();
		}

		private void PerformStartUp()
		{
			UDPHelper.Restart();
			m_TraceConsumer.EnableEventFiring();

			toolTipTimer.Enabled = true;
		}

		private void ShowNormal()
		{
			this.Show();
			this.WindowState = FormWindowState.Normal;

			if (m_LogViewer != null &&
				m_LogViewer.Visible)
			{
				m_LogViewer.Hide();
			}

			this.BringToFront();
			this.Activate();
		}

		private void openToolStripMenuItem_Click(object sender, EventArgs e)
		{
			ShowNormal();
		}


		private void exitToolStripMenuItem_Click(object sender, EventArgs e)
		{
			s_ShutDown = true;
			Close();
		}

		private void notifyIcon_DoubleClick(object sender, EventArgs e)
		{
			ShowMyTraceLog();
		}

		private void contextMenuStrip_Opened(object sender, EventArgs e)
		{
			m_DontShowBalloonsFor5Secs = true;
		}

		private void contextMenuStrip_Closed(object sender, ToolStripDropDownClosedEventArgs e)
		{
			m_DontShowBalloonsFor5Secs = false;
		}

		private void aboutToolStripMenuItem_Click(object sender, EventArgs e)
		{
			frmAbout frm = new frmAbout(m_SPTraceViewIcon);
			frm.StartPosition = FormStartPosition.CenterScreen;
			frm.ShowDialog(this);
		}

		private void clbLevels_ItemCheck(object sender, ItemCheckEventArgs e)
		{
			if (m_Initialized)
			{
				if (e.Index >= 0 &&
					e.Index < clbLevels.Items.Count)
				{
					TraceSeverityEntry entry = (TraceSeverityEntry)clbLevels.Items[e.Index];

					if (e.NewValue == CheckState.Unchecked)
						m_Settings.RemoveMonitoredLevel(entry.TraceSeverity);
					else
						m_Settings.AddMonitoredLevel(entry.TraceSeverity);

					UpdateTraceSettings();
				}
			}
		}

		private void UpdateTraceSettings()
		{
			if (m_Initialized)
			{
				m_Settings.Save();
				UDPHelper.Init(ProcessTraceEvent, m_Settings.FarmRole);
				m_TraceConsumer.UpdateTraceSettings(m_Settings);
			}
		}

		private void btnFilterSettings_Click(object sender, EventArgs e)
		{
			TraceSettings optionsSettings = new TraceSettings(false);
			optionsSettings.CopyFrom(m_Settings);

			frmOptions frm = new frmOptions(m_SPTraceViewIcon, optionsSettings);
			frm.StartPosition = FormStartPosition.CenterParent;
			frm.pnlAllSettings.Enabled = m_ErrorStarting == 0;
			if (frm.ShowDialog(this) == DialogResult.OK)
			{
				Update();
				m_Settings.CopyFrom(frm.Settings);
				UpdateTraceSettings();
			}
		}

		private void SaveTraceActions()
		{
			if (m_Initialized)
			{
				m_Settings.TraceToMyEventsLog = cbxSaveToMyEvents.Checked;
				m_Settings.TraceShowBalloone = cbxShowBalloone.Checked;
				m_Settings.TraceToDebugView = cbxTraceInDebugView.Checked;

				UpdateTraceSettings();
			}
		}

		private void cbxShowBalloone_CheckedChanged(object sender, EventArgs e)
		{
			SaveTraceActions();
		}

		private void cbxSaveToMyEvents_CheckedChanged(object sender, EventArgs e)
		{
			SaveTraceActions();
		}

		private void cbxTraceInDebugView_CheckedChanged(object sender, EventArgs e)
		{
			SaveTraceActions();
		}

		private void notifyIcon_BalloonTipClicked(object sender, EventArgs e)
		{
			if (m_TraceLogEnabled &&
				!m_DontShowBalloonsFor5Secs)
			{
				short rightButtonPressed = GetKeyState(VirtualKeyStates.VK_RBUTTON);
				if (rightButtonPressed >= 0)
					ShowMyTraceLog();
			}
		}

		private void btnViewLog_Click(object sender, EventArgs e)
		{
			ShowMyTraceLog();
		}

		private frmViewer m_LogViewer = null;

		private void ShowMyTraceLog()
		{
			if (!m_Enabled) return;

			string shadowFileName = m_TraceLog.SaveLogFileForViewing();

			if (m_LogViewer == null)
			{
				m_LogViewer = new frmViewer();
				m_LogViewer.Icon = m_SPTraceViewIcon;
			}

			if (File.Exists(shadowFileName))
			{
				m_LogViewer.LoadFile(shadowFileName);
				if (!m_LogViewer.Visible)
					m_LogViewer.Show(this);

				if (m_LogViewer.WindowState == FormWindowState.Minimized)
					m_LogViewer.WindowState = FormWindowState.Maximized;

				m_LogViewer.Activate();
			}
		}

		private void toolTipTimer_Tick(object sender, EventArgs e)
		{
			Debug.WriteLine("toolTipTimer_Tick: " + m_TimerTicks.ToString());

			if (m_NewUpdateAvailable)
			{
				toolTipTimer.Enabled = false;
				SuggestUpdate();
				return;
			}

			BallooneEntry nextEntry = null;
			int timeLength = 5000;
			m_TimerTicks++;

			#region Give 5 sec to the user to select something from the tray menu
			if (m_DontShowBalloonsFor5Secs)
			{
				if (m_BallooneToolTipTicks == -15)
				{
					m_DontShowBalloonsFor5Secs = false;
				}
				else if (m_BallooneToolTipTicks > -10)
				{
					m_BallooneToolTipTicks = -10;
					return;
				}
				else
				{
					m_BallooneToolTipTicks--;
					return;
				}
			}
			#endregion

			lock (m_BalloonesQueue)
			{
				if (m_BalloonesQueue.Count > 0)
				{
					nextEntry = m_BalloonesQueue.Dequeue();
					timeLength = m_BalloonesQueue.Count == 0 ? 10000 : 10000;
					Debug.WriteLine("toolTipTimer_Tick: " + m_BalloonesQueue.Count.ToString()  + " items in the queue. New item dequeued.");
				}
				else
					if (m_BallooneToolTipTicks >= 0)
					{
						m_BallooneToolTipTicks++;
						Debug.WriteLine("toolTipTimer_Tick: Nothing in the queue, showing the current tip for up to 5 secs.");
					}
			}

			if (nextEntry != null)
			{
				if (!string.IsNullOrEmpty(nextEntry.Title) &&
					!string.IsNullOrEmpty(nextEntry.Text))
				{
					notifyIcon.ShowBalloonTip(timeLength, nextEntry.Title, nextEntry.Text, nextEntry.Icon);
					notifyIcon.Tag = nextEntry;
				}
				m_BallooneToolTipTicks = 0;
				Debug.WriteLine("toolTipTimer_Tick: Showing a new item as a balloon");
			}

			if (m_BallooneToolTipTicks > 5)
			{
				Debug.WriteLine("toolTipTimer_Tick: 5 secs are over. Stopped showing the tip.");
				m_BallooneToolTipTicks = -1;
			}

			if ((m_TimerTicks % 60) == 0)
			{
				m_TraceLog.Flush();
			}
		}

		private void notifyIcon_BalloonTipClosed(object sender, EventArgs e)
		{
			//// Once a balloone has been closed, don't show more events
			//lock (m_BalloonesQueue)
			//{
			//    Trace.WriteLine("notifyIcon_BalloonTipClosed: Clearing " + m_BalloonesQueue.Count.ToString() + " items frm the queue.");
			//    m_BalloonesQueue.Clear();
			//}
		}

		private void miEnabledDisabled_Click(object sender, EventArgs e)
		{
			if (m_Enabled)
			{
				m_Enabled = false;
				lock (m_BalloonesQueue)
				{
					m_BalloonesQueue.Clear();
				}

				notifyIcon.Text = "SPTraceView (Disabling ...)";
				notifyIcon.ContextMenuStrip = null;
				try
				{
					PerformShutdownButDontQuit();
				}
				finally
				{
					notifyIcon.Text = "SPTraceView";
					notifyIcon.ContextMenuStrip = contextMenuStrip;
				}
				

				miEnabledDisabled.Image = m_SPTraceViewDisabledBitmap;
				miEnabledDisabled.Text = "&Enable";
				notifyIcon.Icon = m_SPTraceViewDisabledIcon;
				Update();
			}
			else
			{
				PerformStartUp();

				m_Enabled = true;
				miEnabledDisabled.Image = Properties.Resources.WSS;
				miEnabledDisabled.Text = "&Disable";
				notifyIcon.Icon = m_SPTraceViewIcon;
				Update();
			}
		}

		private void frmMain_Shown(object sender, EventArgs e)
		{
			m_TraceLogEnabled = true;
		}

		private void frmMain_Resize(object sender, EventArgs e)
		{
			if (this.WindowState == FormWindowState.Minimized)
				this.Hide();
		}

	}


}